package com.handa.documentManager.service.impl;


import com.handa.common.exception.ServiceException;
import com.handa.documentManager.entity.DTO.FileObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import java.util.stream.Collectors;

@Service
@Slf4j
public class FileService {

    public List<FileObject> listFiles(String path) throws IOException {
        Path fullPath = getFullPath(path);
        File directory = fullPath.toFile();

        if (!directory.exists() || !directory.isDirectory()) {
            throw new IllegalArgumentException("Invalid directory path");
        }

        File[] files = directory.listFiles();
        if (files == null) {
            return new ArrayList<>();
        }

        return java.util.Arrays.stream(files)
                .map(file -> new FileObject(
                        file.getName(),
                        file.getAbsolutePath().replace("\\", "/"),
                        file.isDirectory(),
                        file.length(),
                        new Date(file.lastModified())

                ))
                .collect(Collectors.toList());
    }

    public String storeFile(String fileName, String targetPath, MultipartFile file) {
        log.info("fileName: " + fileName + " path: " + targetPath + " originName: " + file.getOriginalFilename() + " fileSize: " + file.getSize());
        String finalFileName = file.getOriginalFilename();
        if (StringUtils.isNotBlank(fileName)) {
            finalFileName = fileName;
        }
        if (file.isEmpty()) {
            return "Please select a file to upload.";
        }
        try {
            if (!targetPath.endsWith("/")) {
                targetPath = targetPath + "/";
            }
            File uploadedFile = new File(targetPath + finalFileName);
            file.transferTo(uploadedFile);
            return "File uploaded successfully!";
        } catch (IOException e) {
            e.printStackTrace();
            return "File upload failed!";
        }
    }

    public InputStream downloadFile(File file) throws IOException {
        if (!file.exists() || file.isDirectory()) {
            return null;
        }

        InputStream res = new FileInputStream(file);

        return res;
    }

    public boolean newFolder(String folderPath) {
        Path path = Paths.get(folderPath);

        try {
            // 创建目录及其所有不存在的父目录
            Files.createDirectories(path);
            return true;
        } catch (Exception e) {
            log.error("创建失败: " + e.getMessage());
        }
        return false;
    }

    /**
     * 移动文件到指定目录
     *
     * @param sourceFilePath  源文件路径
     * @param targetDirectory 目标目录路径
     * @return 移动成功返回true，否则返回false
     */
    public boolean moveFile(String sourceFilePath, String targetDirectory) {
        Path sourcePath = Paths.get(sourceFilePath);
        Path targetDirPath = Paths.get(targetDirectory);

        try {
            // 检查源文件是否存在
            if (!Files.exists(sourcePath)) {
                log.error("源文件不存在: {}", sourceFilePath);
                return false;
            }

            // 确保目标目录存在，如果不存在则创建
            if (!Files.exists(targetDirPath)) {
                Files.createDirectories(targetDirPath);
                log.info("创建目标目录: {}", targetDirectory);
            }

            // 构建目标文件路径（保持原文件名）
            Path targetPath = targetDirPath.resolve(sourcePath.getFileName());

            // 移动文件，如果目标文件已存在则替换
            Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
            log.info("文件移动成功: {} -> {}", sourceFilePath, targetPath);

            return true;

        } catch (Exception e) {
            log.error("移动文件失败: {}", e.getMessage(), e);
            return false;
        }
    }

    /**
     * 移动文件夹到另一个文件夹（目标路径包含源文件夹名称）
     * @param sourceFolderPath 源文件夹路径
     * @param targetParentPath 目标父文件夹路径
     * @return 移动成功返回true，否则返回false
     */
    public boolean moveFolder(String sourceFolderPath, String targetParentPath) {
        Path sourcePath = Paths.get(sourceFolderPath);
        Path targetParent = Paths.get(targetParentPath);

        try {
            // 检查源文件夹是否存在
            if (!Files.exists(sourcePath) || !Files.isDirectory(sourcePath)) {
                log.error("源文件夹不存在或不是目录: {}", sourceFolderPath);
                return false;
            }

            // 获取源文件夹名称
            String sourceFolderName = sourcePath.getFileName().toString();

            // 构建目标路径（包含源文件夹名称）
            Path targetPath = targetParent.resolve(sourceFolderName);

            // 检查目标文件夹是否与源文件夹相同
            if (sourcePath.equals(targetPath)) {
                log.error("源文件夹和目标文件夹不能相同");
                return false;
            }

            // 检查目标文件夹是否是源文件夹的子文件夹
            if (targetPath.startsWith(sourcePath)) {
                log.error("不能将文件夹移动到自身的子文件夹中");
                return false;
            }

            // 确保目标父目录存在
            if (!Files.exists(targetParent)) {
                Files.createDirectories(targetParent);
            }

            // 如果目标文件夹已存在，先删除（可选，根据需求调整）
            if (Files.exists(targetPath)) {
                log.warn("目标文件夹已存在，将被覆盖: {}", targetPath);
                deleteFolder(targetPath);
            }

            // 执行移动操作
            Files.move(sourcePath, targetPath, StandardCopyOption.REPLACE_EXISTING);
            log.info("文件夹移动成功: {} -> {}", sourceFolderPath, targetPath);
            return true;

        } catch (DirectoryNotEmptyException e) {
            log.error("目标文件夹不为空，无法移动: {}", e.getMessage());
            return false;
        } catch (FileAlreadyExistsException e) {
            log.error("目标文件夹已存在: {}", e.getMessage());
            return false;
        } catch (IOException e) {
            log.error("移动文件夹失败: {}", e.getMessage(), e);
            return false;
        }
    }

    public boolean newFile(String _filePath) {
        // 设置文件路径
        Path filePath = Paths.get(_filePath);

        try {
            // 创建新文件，如果父目录不存在，则会抛出异常
            Files.createFile(filePath);
            return true;
        } catch (Exception e) {
            log.error("创建文件失败： " + e);
        }

        return false;
    }

    public boolean renameFile(String originalPath, String newName) throws IOException {
        Path sourcePath = Paths.get(originalPath);
        Path targetPath = sourcePath.resolveSibling(newName);

        // 检查源文件是否存在
        if (!Files.exists(sourcePath)) {
            throw new FileNotFoundException("Source file not found: " + originalPath);
        }

        // 检查目标文件是否已存在
        if (Files.exists(targetPath)) {
            throw new IOException("Target file already exists: " + targetPath);
        }

        // 执行重命名
        Files.move(sourcePath, targetPath);
        return true;
    }

    public boolean renameDirectory(String originalPath, String newName) throws IOException {
        Path sourcePath = Paths.get(originalPath);
        Path targetPath = sourcePath.resolveSibling(newName);

        // 验证源文件夹是否存在
        if (!Files.exists(sourcePath)) {
            throw new FileNotFoundException("Source directory not found: " + originalPath);
        }

        // 验证是否是目录
        if (!Files.isDirectory(sourcePath)) {
            throw new IOException("Source is not a directory: " + originalPath);
        }

        // 验证目标文件夹是否已存在
        if (Files.exists(targetPath)) {
            throw new IOException("Target directory already exists: " + targetPath);
        }

        // 执行重命名
        Files.move(sourcePath, targetPath);
        return true;
    }


    public boolean deleteFile(String _filePath) {
        Path filePath = Paths.get(_filePath); // 替换为你的文件路径

        try {
            FileUtils.forceDelete(new File(_filePath));
            return true;
        } catch (NoSuchFileException e) {
            throw new ServiceException("文件不存在: " + filePath);
        } catch (IOException e) {
            throw new ServiceException("删除失败，可能原因：权限不足、文件被占用等");
        }
    }

    public boolean deleteFolder(String folderPath) {
        Path dirPath = Paths.get(folderPath);
        return deleteFolder(dirPath);
    }

    public boolean deleteFolder(Path dirPath) {
        try {
            Files.walkFileTree(dirPath, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Files.delete(file);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    Files.delete(dir);
                    return FileVisitResult.CONTINUE;
                }
            });
            return true;
        } catch (IOException e) {
            log.info("删除文件出错" + e);
        }
        return false;
    }

    public String readTextFile(String filePath) throws IOException {
        // 使用 StringBuilder 来构建最终的字符串，因为它是线程不安全的，在单线程环境下效率更高。
        StringBuilder fileData = new StringBuilder();
        // 创建一个 FileReader 对象来读取文件
        Reader reader = new FileReader(filePath);
        // 使用 BufferedReader 来提高读取效率
        BufferedReader bufferedReader = new BufferedReader(reader);

        char[] buf = new char[1024];
        int numRead = 0;
        // 循环读取文件内容
        while ((numRead = bufferedReader.read(buf)) != -1) {
            // 将读取的内容添加到 StringBuilder 中
            String readData = String.valueOf(buf, 0, numRead);
            fileData.append(readData);
        }

        // 关闭 BufferedReader 和 FileReader
        bufferedReader.close();
        return fileData.toString();
    }

    private Path getFullPath(String path) {
        if (path == null || path.isEmpty()) {
            throw new ServiceException("选择的路径为空");
        }
        return Paths.get(path);
    }
}